// C source file with the MEM_SPACE.h function implementations

// create_mem_space()
// create a mem_space struct to assign to the MEM_SPACE_TB
// the function returns a pointer to the mem_space element
mem_space * create_mem_space(umax size)
{  
  // check global error
  mem_space * space = NULL;
  if (size == 0 || MEM_SPACE_GLOB_ERR != MEM_SPACE_NO_ERR)
    goto end;  
  
  // create a new mem_space variable into a free slot in the memory space table
  for (umax i = 0; i < MEM_SPACE_TB_LENGTH; i++)
    if (MEM_SPACE_TB[i].ptr == NULL) {
      // allocate memory with calloc()
      MEM_SPACE_TB[i].ptr = calloc(size, 1);
      if (MEM_SPACE_TB[i].ptr == NULL)
        goto end;
      MEM_SPACE_TB[i].size = size;
      MEM_SPACE_TB_FREE_SPACE--;
      space = &MEM_SPACE_TB[i];
      break;
    }
  
  // no space left on the table
  if (space == NULL) 
    MEM_SPACE_GLOB_ERR = MEM_SPACE_TB_FULL;
  
  // return whatever happened
  end:
  return space;
}

// free_mem_space()
// function to free the memory allocated inside a mem_space structure
umax free_mem_space(mem_space * space)
{  
  // check if the pointer is valid
  if (space != NULL && space -> ptr != NULL) {
    // search for the equivalent structure in the space table to remove it
    for (umax i = 0; i < MEM_SPACE_TB_LENGTH; i++)
      if (MEM_SPACE_TB[i].ptr == space -> ptr
          && MEM_SPACE_TB[i].size == space -> size) {
        // free the memory only if it is was created by calloc()
        // in other words, if it was registered on MEM_SPACE_TB
        free(space -> ptr);
        MEM_SPACE_TB[i].ptr = NULL;
        MEM_SPACE_TB[i].size = 0;
        MEM_SPACE_TB_FREE_SPACE++;
        break;
      }
  }  
  // return free slot count
  return MEM_SPACE_TB_FREE_SPACE;
}

// print_mem_space()
// function to print the information stored in a mem_space structure located somewhere in memory
umax print_mem_space(byte * src, umax size)
{
  // check params
  if (src == NULL || size < MEM_SPACE_SIZE)
    return 0;
  
  // otherwise print the structure info
  mem_space * space = (mem_space *) src;
  printf("MEM_SPACE structure info:\n");
  printf("Pointer: %p\n", space -> ptr);
  printf("Size (bytes): %llu\n", space -> size);
  return MEM_SPACE_SIZE;
}

// print_mem_space_tb_err()
// function to print the error code stored in MEM_SPACE_GLOB_ERR
void print_mem_space_tb_err(void)
{
  // evaluate the error
  switch(MEM_SPACE_GLOB_ERR) {
    case MEM_SPACE_NO_ERR: 
      printf("\nMEM_SPACE_ERR: NO ERROR (%d)\n", MEM_SPACE_NO_ERR);
      break;
    case MEM_SPACE_TB_FULL: 
      printf("\nMEM_SPACE_ERR: SPACE TABLE FULL (%d)\n", MEM_SPACE_TB_FULL);
      break;
    case MEM_SPACE_CALLOC_FAIL: 
      printf("\nMEM_SPACE_ERR: CALLOC FAIL (%d)\n", MEM_SPACE_CALLOC_FAIL);
      break;
  }
  return;
}
